package com.fkdx.common.token;

import com.fkdx.common.constant.SysConstant;
import com.google.gson.Gson;
import com.fkdx.common.dto.sys.CurrentUserDTO;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.SignatureException;
import org.joda.time.DateTime;
import org.springframework.stereotype.Component;

/**
 * TokenUtil
 *
 * @author Chopper
 * @version v1.0
 * 2020-11-12 18:44
 */
@Component
public class TokenUtil {

    //#token过期时间 默认8小时
    private static final long tokenExpireTime = 9 * 60;


    /**
     * 构建token
     *
     * @param username 主体
     * @param claim    私有声明
     * @param longTerm 长时间特殊token 如：移动端，微信小程序等
     * @return TOKEN
     */
    public TokenDomain createToken(String username, Object claim, boolean longTerm) {
        TokenDomain token = new TokenDomain();
        //访问token
        //刷新token生成策略：如果是长时间有效的token（用于app），则默认15天有效期刷新token。如果是普通用户登录，则刷新token为普通token2倍数
        Long expireTime = longTerm ? 60 * 24 * 30 : tokenExpireTime ;
        String accessToken = createToken(username, claim, expireTime);
        String refreshToken = createToken(username, claim, expireTime);

        token.setAccessToken(accessToken);
        token.setRefreshToken(refreshToken);
        return token;
    }

    /**
     * 刷新token
     *
     * @param oldRefreshToken 刷新token
     * @return token
     */
    public TokenDomain refreshToken(String oldRefreshToken) throws Exception {

        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(SecretKeyUtil.generalKeyByDecoders())
                    .parseClaimsJws(oldRefreshToken).getBody();
        } catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | SignatureException |
                 IllegalArgumentException e) {
            //token 过期 认证失败等
            throw new Exception("用户已过期，请重新登录");
        }

        //获取存储在claims中的用户信息
        String json = claims.get(SysConstant.ACCESSTOKEN).toString();
        CurrentUserDTO authUser = new Gson().fromJson(json, CurrentUserDTO.class);


        String username = authUser.getUserName();
        //获取是否长期有效的token
        boolean longTerm = false;


        TokenDomain token = new TokenDomain();
        //访问token
        String accessToken = createToken(username, authUser, tokenExpireTime);

        //如果是信任登录设备，则刷新token长度继续延长
        Long expirationTime = tokenExpireTime * 2;
        if (longTerm) {
            expirationTime = 60 * 24 * 15L;
        }

        //刷新token生成策略：如果是长时间有效的token（用于app），则默认15天有效期刷新token。如果是普通用户登录，则刷新token为普通token2倍数
        String refreshToken = createToken(username, authUser, expirationTime);

        token.setAccessToken(accessToken);
        token.setRefreshToken(refreshToken);
        return token;

    }

    /**
     * 生成token
     *
     * @param username       主体
     * @param claim          私有神明内容
     * @param expirationTime 过期时间（分钟）
     * @return token字符串
     */
    private String createToken(String username, Object claim, Long expirationTime) {
        DateTime dateTime = new DateTime();
        //JWT 生成
        return Jwts.builder()
                //jwt 私有声明
                .claim(SysConstant.ACCESSTOKEN, new Gson().toJson(claim))
                //JWT的主体
                .setSubject(username)
                //失效时间 当前时间+过期分钟
                .setExpiration(dateTime.plusMinutes(Integer.parseInt(expirationTime.toString())).toDate())
                //签名算法和密钥
                .signWith(SecretKeyUtil.generalKey())
                .compact();
    }
}
